package week04.necessary;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.Supplier;

public class ShutdownOnFinished {

    public static void main(String[] args) throws Exception {
        long start = System.currentTimeMillis();

        //////////////////////////////// 在这里创建一个线程或线程池
        ExecutorService executorService = Executors.newSingleThreadExecutor();

        //////////////////////////////// 异步执行 下面方法；线程池方式
        // #1 CompletableFuture异步执行
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(ShutdownOnFinished::sum);
        int result = future.get();


//        // #2 shutdownNow｜shutdown 配合 isTerminated 阻塞
//        MyTask<Integer> myTask = new MyTask<>(ShutdownOnFinished::sum);
//        executorService.execute(myTask);
//        executorService.shutdown();
//        // executorService.shutdownNow();
//        while (!executorService.isTerminated()) {
//        TimeUnit.MILLISECONDS.sleep(1);
//        }
//        int result = myTask.getData();


//        // #3 使用 Future#get()阻塞特性
//        Future<Integer> future = executorService.submit(ShutdownOnFinished::sum);
//        executorService.shutdownNow();
//        int result = future.get();

//        // #4 利用 ExecutorServer#invokeAll方法阻塞所有任务完成
//        List<Future<Integer>> futures = executorService.invokeAll(Collections.singletonList(ShutdownOnFinished::sum));
//        executorService.shutdownNow();
//        int result = futures.get(0).get();

//        // #5 利用 ExecutorCompletionService#take 阻塞弹出已完成的任务
//        ExecutorCompletionService<Integer> executorCompletionService = new ExecutorCompletionService<>(executorService);
//        executorCompletionService.submit(ShutdownOnFinished::sum);
//        Future<Integer> take = executorCompletionService.take();
//        int result = take.get();

//        // #6 利用 Thread#join 阻塞 主线程
//        MyTask<Integer> myTask = new MyTask<>(ShutdownOnFinished::sum);
//        Thread thread = new Thread(myTask);
//        thread.start();
//        thread.join();
//        int result = myTask.getData();


//        // #7 利用 Thread#isAlive直接判断线程存活状态
//        MyTask<Integer> myTask = new MyTask<>(ShutdownOnFinished::sum);
//        Thread thread = new Thread(myTask);
//        thread.start();
//        while (thread.isAlive()) {
//            TimeUnit.MILLISECONDS.sleep(1);
//        }
//        int result = myTask.getData();


//        // #8 利用 CountDownLatch 阻塞主线程
//        CountDownLatch countDownLatch = new CountDownLatch(1);
//        MyTask<Integer> myTask = new MyTask<>(() -> {
//            try {
//                return sum();
//            } finally {
//                countDownLatch.countDown();
//            }
//        });
//
//        new Thread(myTask).start();
//
//        countDownLatch.await();
//        int result = myTask.getData();


//        // #9 利用CyclicBarrier 阻塞
//        CyclicBarrier cyclicBarrier = new CyclicBarrier(2);
//        MyTask<Integer> myTask = new MyTask<>(() -> {
//            try {
//                int sum = sum();
//                cyclicBarrier.await();
//                return sum;
//            } catch (InterruptedException | BrokenBarrierException e) {
//                e.printStackTrace();
//            }
//            return null;
//        });
//
//        new Thread(myTask).start();
//
//        cyclicBarrier.await();
//        int result = myTask.getData();

//        // #10 利用 Phaser 阻塞
//        Phaser phaser = new Phaser(2);
//        MyTask<Integer> myTask = new MyTask<>(() -> {
//            try {
//                return sum();
//            } finally {
//                phaser.arriveAndDeregister();
//            }
//        });
//
//        new Thread(myTask).start();
//
//        phaser.arriveAndAwaitAdvance();
//        int result = myTask.getData();


        // #11 利用 Semaphore 阻塞
//        Semaphore semaphore = new Semaphore(1);
//        semaphore.acquire();
//
//        MyTask<Integer> myTask = new MyTask<>(() -> {
//            try {
//                return sum();
//            } finally {
//                semaphore.release();
//            }
//        });
//
//        new Thread(myTask).start();
//
//        semaphore.acquire();
//        int result = myTask.getData();


//        // #12 利用 LockSupport#park 阻塞
//        Thread mainThread = Thread.currentThread();
//        MyTask<Integer> myTask = new MyTask<>(() -> {
//            try {
//                int sum = sum();
//                // 稍微休眠、让主线程 先执行 LockSupport.park();若不行，稍微调大 睡眠时长即可
//                TimeUnit.MILLISECONDS.sleep(1);
//                return sum;
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            } finally {
//                LockSupport.unpark(mainThread);
//            }
//            return null;
//        });
//
//        new Thread(myTask).start();
//
//        LockSupport.park();
//        int result = myTask.getData();


        // #13 利用 BlockingQueue#take 阻塞
//        BlockingQueue<Integer> blockingQueue = new LinkedBlockingDeque<>();
//        new Thread(() -> blockingQueue.add(sum())).start();
//        int result = blockingQueue.take();


//        // #14 自定义执行结束标识阻塞
//        AtomicBoolean atomicBoolean = new AtomicBoolean(false);
//        MyTask<Integer> myTask = new MyTask<>(() -> {
//            try {
//                return sum();
//            } finally {
//                atomicBoolean.set(true);
//            }
//        });
//
//        new Thread(myTask).start();
//
//        while (!atomicBoolean.get()) {
//            TimeUnit.MILLISECONDS.sleep(1);
//        }
//
//        int result = myTask.getData();


        //////////////////////////////// 确保  拿到result 并输出
        System.out.println("异步计算结果为：" + result);
        System.out.println("使用时间：" + (System.currentTimeMillis() - start) + " ms");
        // 然后退出main线程
    }

    private static int sum() {
        return fibo(36);
    }

    private static int fibo(int a) {
        if (a < 2) {
            return 1;
        }
        return fibo(a - 1) + fibo(a - 2);
    }

    static class MyTask<T> implements Runnable {
        private T data;
        private final Supplier<T> supplier;

        MyTask(Supplier<T> supplier) {
            this.supplier = supplier;
        }

        public T getData() {
            return data;
        }

        @Override
        public void run() {
            data = supplier.get();
        }
    }
}
